package com.opencee.cloud.api.gateway.listener;

import com.alibaba.fastjson.JSONObject;
import com.opencee.cloud.base.constants.BaseApiSchemeType;
import com.opencee.cloud.base.event.ApiPublishEvent;
import com.opencee.cloud.base.vo.BaseApiVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.actuate.AbstractGatewayControllerEndpoint;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.LinkedList;
import java.util.List;

/**
 * @author liuyadu
 */
@Slf4j
@Component
public class ApiPublishEventListener implements ApplicationListener<ApiPublishEvent> {

    @Autowired
    private AbstractGatewayControllerEndpoint endpoint;

    @Override
    public void onApplicationEvent(ApiPublishEvent event) {
        log.info("Received ApiPublishEvent - message: {}", event);
        List<BaseApiVO> list = event.getApiList();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        list.forEach(t -> {
            RouteDefinition routeDefinition = this.buildRouterDefinition(t);
            if (routeDefinition != null) {
                endpoint.save(t.getId().toString(), routeDefinition).subscribe();
            }
        });
    }


    public static void main(String[] args) {
        System.out.println(NameUtils.normalizeFilterFactoryName(HystrixGatewayFilterFactory.class));
        System.out.println(NameUtils.normalizeFilterFactoryName(SetPathGatewayFilterFactory.class));
    }

    /**
     * 构建路由定义信息
     *
     * @param api
     */
    public RouteDefinition buildRouterDefinition(BaseApiVO api) {
        RouteDefinition routeDefinition = null;
        if (api.getId() != null && api.getMeta() != null) {
            routeDefinition = new RouteDefinition();
            JSONObject metadata = api.getMeta();
            String requestPath = api.getPath();
            String method = metadata.getString("method");
            String scheme = metadata.getString("scheme");
            // 后端服务类型:1-服务负载 2-网络地址
            String serverType = metadata.getString("serverType");
            // 后端服务地址
            String serverUrl = metadata.getString("serverUrl");
            // 后端请求Path
            String serverPath = metadata.getString("serverPath");
            List<PredicateDefinition> predicates = new LinkedList<>();
            List<FilterDefinition> filters = new LinkedList<>();

            PredicateDefinition prePath = new PredicateDefinition();
            prePath.setName("Path");
            prePath.addArg("pattern", requestPath);
            predicates.add(prePath);

            if (StringUtils.isNotBlank(method)) {
                PredicateDefinition preMethod = new PredicateDefinition();
                preMethod.setName("Method");
                preMethod.addArg("method", method);
                predicates.add(preMethod);
            }
            UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
            if ("1".equals(serverType)) {
                if (BaseApiSchemeType.WEBSOCKET.getValue().equals(scheme)) {
                    // uri = lb:ws://msg-service
                    builder.scheme("lb:" + scheme);
                } else {
                    // uri = lb://uaa-service
                    builder.scheme("lb://");
                }
            } else {
                //  uri = http|https|ws://test.com
                builder.scheme(scheme);
            }
            builder.path(serverPath);

            // 设置服务端地址
            FilterDefinition setPath = new FilterDefinition();
            setPath.setName("SetPath");
            setPath.addArg("template", serverPath);
            filters.add(setPath);

            // 熔断
            FilterDefinition hystrix = new FilterDefinition();
            hystrix.setName("Hystrix");
            hystrix.addArg("name", "fallbackcmd");
            hystrix.addArg("fallbackUri", "forward:/fallback");
            filters.add(hystrix);
            routeDefinition.setId(api.getId().toString());
            routeDefinition.setUri(builder.build().toUri());
            routeDefinition.setPredicates(predicates);
            routeDefinition.setFilters(filters);
            routeDefinition.setMetadata(metadata);
        }
        return routeDefinition;
    }

}